/** 
// https://github.com/alsey/wxbarcode
// https://github.com/alsey/wxbarcode
// 最后一位显示 _ 问题
// https://github.com/alsey/wxbarcode/issues/2
// //ok some type of shift is nessecary if (shifter != -1) { result.push(shifter); result.push(codeValue(chr1));//把这里的chr2改成chr1即可。 }
**/
 
!(function(){
    var CHAR_TILDE = 126;
    var CODE_FNC1 = 102;
     
    var SET_STARTA = 103;
    var SET_STARTB = 104;
    var SET_STARTC = 105;
    var SET_SHIFT = 98;
    var SET_CODEA = 101;
    var SET_CODEB = 100;
    var SET_STOP = 106;
     
     
    var REPLACE_CODES = {
        CHAR_TILDE: CODE_FNC1 //~ corresponds to FNC1 in GS1-128 standard
    }
     
    var CODESET = {
        ANY: 1,
        AB: 2,
        A: 3,
        B: 4,
        C: 5
    };
     
    function getBytes(str) {
        var bytes = [];
        for (var i = 0; i < str.length; i++) {
            bytes.push(str.charCodeAt(i));
        }
        return bytes;
    }
     
    exports.code128 = function (ctx, text, width, height) {
     
        width = parseInt(width);
     
        height = parseInt(height);
     
        var codes = stringToCode128(text);
     
        var g = new Graphics(ctx, width, height);
     
        var barWeight = g.area.width / ((codes.length - 3) * 11 + 35);
     
        var x = g.area.left;
        var y = g.area.top;
        for (var i = 0; i < codes.length; i++) {
            var c = codes[i];
            //two bars at a time: 1 black and 1 white
            for (var bar = 0; bar < 8; bar += 2) {
                var barW = PATTERNS[c][bar] * barWeight;
                // var barH = height - y - this.border;
                var barH = height - y;
                var spcW = PATTERNS[c][bar + 1] * barWeight;
     
                //no need to draw if 0 width
                if (barW > 0) {
                    g.fillFgRect(x, y, barW, barH);
                }
     
                x += barW + spcW;
            }
        }
     
        ctx.draw();
    }
     
     
    function stringToCode128(text) {
     
        var barc = {
            currcs: CODESET.C
        };
     
        var bytes = getBytes(text);
        //decide starting codeset
        var index = bytes[0] == CHAR_TILDE ? 1 : 0;
     
        var csa1 = bytes.length > 0 ? codeSetAllowedFor(bytes[index++]) : CODESET.AB;
        var csa2 = bytes.length > 0 ? codeSetAllowedFor(bytes[index++]) : CODESET.AB;
        barc.currcs = getBestStartSet(csa1, csa2);
        barc.currcs = perhapsCodeC(bytes, barc.currcs);
     
        //if no codeset changes this will end up with bytes.length+3
        //start, checksum and stop
        var codes = new Array();
     
        switch (barc.currcs) {
            case CODESET.A:
                codes.push(SET_STARTA);
                break;
            case CODESET.B:
                codes.push(SET_STARTB);
                break;
            default:
                codes.push(SET_STARTC);
                break;
        }
     
     
        for (var i = 0; i < bytes.length; i++) {
            var b1 = bytes[i]; //get the first of a pair
            //should we translate/replace
            if (b1 in REPLACE_CODES) {
                codes.push(REPLACE_CODES[b1]);
                i++ //jump to next
                b1 = bytes[i];
            }
     
            //get the next in the pair if possible
            var b2 = bytes.length > (i + 1) ? bytes[i + 1] : -1;
     
            codes = codes.concat(codesForChar(b1, b2, barc.currcs));
            //code C takes 2 chars each time
            if (barc.currcs == CODESET.C) i++;
        }
     
        //calculate checksum according to Code 128 standards
        var checksum = codes[0];
        for (var weight = 1; weight < codes.length; weight++) {
            checksum += (weight * codes[weight]);
        }
        codes.push(checksum % 103);
     
        codes.push(SET_STOP);
     
        //encoding should now be complete
        return codes;
     
        function getBestStartSet(csa1, csa2) {
            //tries to figure out the best codeset
            //to start with to get the most compact code
            var vote = 0;
            vote += csa1 == CODESET.A ? 1 : 0;
            vote += csa1 == CODESET.B ? -1 : 0;
            vote += csa2 == CODESET.A ? 1 : 0;
            vote += csa2 == CODESET.B ? -1 : 0;
            //tie goes to B due to my own predudices
            return vote > 0 ? CODESET.A : CODESET.B;
        }
     
        function perhapsCodeC(bytes, codeset) {
            for (var i = 0; i < bytes.length; i++) {
                var b = bytes[i]
                if ((b < 48 || b > 57) && b != CHAR_TILDE)
                    return codeset;
            }
            return CODESET.C;
        }
     
        //chr1 is current byte
        //chr2 is the next byte to process. looks ahead.
        function codesForChar(chr1, chr2, currcs) {
            var result = [];
            var shifter = -1;
     
            if (charCompatible(chr1, currcs)) {
                if (currcs == CODESET.C) {
                    if (chr2 == -1) {
                        shifter = SET_CODEB;
                        currcs = CODESET.B;
                    }
                    else if ((chr2 != -1) && !charCompatible(chr2, currcs)) {
                        //need to check ahead as well
                        if (charCompatible(chr2, CODESET.A)) {
                            shifter = SET_CODEA;
                            currcs = CODESET.A;
                        }
                        else {
                            shifter = SET_CODEB;
                            currcs = CODESET.B;
                        }
                    }
                }
            }
            else {
                //if there is a next char AND that next char is also not compatible
                if ((chr2 != -1) && !charCompatible(chr2, currcs)) {
                    //need to switch code sets
                    switch (currcs) {
                        case CODESET.A:
                            shifter = SET_CODEB;
                            currcs = CODESET.B;
                            break;
                        case CODESET.B:
                            shifter = SET_CODEA;
                            currcs = CODESET.A;
                            break;
                    }
                }
                else {
                    //no need to shift code sets, a temporary SHIFT will suffice
                    shifter = SET_SHIFT;
                }
            }
     
            //ok some type of shift is nessecary
            if (shifter != -1) {
                result.push(shifter);
                result.push(codeValue(chr1));
            }
            else {
                if (currcs == CODESET.C) {
                    //include next as well
                    result.push(codeValue(chr1, chr2));
                }
                else {
                    result.push(codeValue(chr1));
                }
            }
            barc.currcs = currcs;
     
            return result;
        }
    }
     
    //reduce the ascii code to fit into the Code128 char table
    function codeValue(chr1, chr2) {
        if (typeof chr2 == "undefined") {
            return chr1 >= 32 ? chr1 - 32 : chr1 + 64;
        }
        else {
            return parseInt(String.fromCharCode(chr1) + String.fromCharCode(chr2));
        }
    }
     
    function charCompatible(chr, codeset) {
        var csa = codeSetAllowedFor(chr);
        if (csa == CODESET.ANY) return true;
        //if we need to change from current
        if (csa == CODESET.AB) return true;
        if (csa == CODESET.A && codeset == CODESET.A) return true;
        if (csa == CODESET.B && codeset == CODESET.B) return true;
        return false;
    }
     
    function codeSetAllowedFor(chr) {
        if (chr >= 48 && chr <= 57) {
            //0-9
            return CODESET.ANY;
        }
        else if (chr >= 32 && chr <= 95) {
            //0-9 A-Z
            return CODESET.AB;
        }
        else {
            //if non printable
            return chr < 32 ? CODESET.A : CODESET.B;
        }
    }
     
    var Graphics = function(ctx, width, height) {
     
        this.width = width;
        this.height = height;
        this.quiet = Math.round(this.width / 40);
     
        this.border_size   = 0;
        this.padding_width = 0;
     
        this.area = {
            width : width - this.padding_width * 2 - this.quiet * 2,
            height: height - this.border_size * 2,
            top   : this.border_size - 4,
            left  : this.padding_width + this.quiet
        };
     
        this.ctx = ctx;
        this.fg = "#000000";
        this.bg = "#ffffff";
     
        // fill background
        this.fillBgRect(0,0, width, height);
     
        // fill center to create border
        this.fillBgRect(0, this.border_size, width, height - this.border_size * 2);
    }
     
    //use native color
    Graphics.prototype._fillRect = function(x, y, width, height, color) {
        this.ctx.setFillStyle(color)
        this.ctx.fillRect(x, y, width, height)
    }
     
    Graphics.prototype.fillFgRect = function(x,y, width, height) {
        this._fillRect(x, y, width, height, this.fg);
    }
     
    Graphics.prototype.fillBgRect = function(x,y, width, height) {
        this._fillRect(x, y, width, height, this.bg);
    }
     
    var PATTERNS = [
        [2, 1, 2, 2, 2, 2, 0, 0],  // 0
        [2, 2, 2, 1, 2, 2, 0, 0],  // 1
        [2, 2, 2, 2, 2, 1, 0, 0],  // 2
        [1, 2, 1, 2, 2, 3, 0, 0],  // 3
        [1, 2, 1, 3, 2, 2, 0, 0],  // 4
        [1, 3, 1, 2, 2, 2, 0, 0],  // 5
        [1, 2, 2, 2, 1, 3, 0, 0],  // 6
        [1, 2, 2, 3, 1, 2, 0, 0],  // 7
        [1, 3, 2, 2, 1, 2, 0, 0],  // 8
        [2, 2, 1, 2, 1, 3, 0, 0],  // 9
        [2, 2, 1, 3, 1, 2, 0, 0],  // 10
        [2, 3, 1, 2, 1, 2, 0, 0],  // 11
        [1, 1, 2, 2, 3, 2, 0, 0],  // 12
        [1, 2, 2, 1, 3, 2, 0, 0],  // 13
        [1, 2, 2, 2, 3, 1, 0, 0],  // 14
        [1, 1, 3, 2, 2, 2, 0, 0],  // 15
        [1, 2, 3, 1, 2, 2, 0, 0],  // 16
        [1, 2, 3, 2, 2, 1, 0, 0],  // 17
        [2, 2, 3, 2, 1, 1, 0, 0],  // 18
        [2, 2, 1, 1, 3, 2, 0, 0],  // 19
        [2, 2, 1, 2, 3, 1, 0, 0],  // 20
        [2, 1, 3, 2, 1, 2, 0, 0],  // 21
        [2, 2, 3, 1, 1, 2, 0, 0],  // 22
        [3, 1, 2, 1, 3, 1, 0, 0],  // 23
        [3, 1, 1, 2, 2, 2, 0, 0],  // 24
        [3, 2, 1, 1, 2, 2, 0, 0],  // 25
        [3, 2, 1, 2, 2, 1, 0, 0],  // 26
        [3, 1, 2, 2, 1, 2, 0, 0],  // 27
        [3, 2, 2, 1, 1, 2, 0, 0],  // 28
        [3, 2, 2, 2, 1, 1, 0, 0],  // 29
        [2, 1, 2, 1, 2, 3, 0, 0],  // 30
        [2, 1, 2, 3, 2, 1, 0, 0],  // 31
        [2, 3, 2, 1, 2, 1, 0, 0],  // 32
        [1, 1, 1, 3, 2, 3, 0, 0],  // 33
        [1, 3, 1, 1, 2, 3, 0, 0],  // 34
        [1, 3, 1, 3, 2, 1, 0, 0],  // 35
        [1, 1, 2, 3, 1, 3, 0, 0],  // 36
        [1, 3, 2, 1, 1, 3, 0, 0],  // 37
        [1, 3, 2, 3, 1, 1, 0, 0],  // 38
        [2, 1, 1, 3, 1, 3, 0, 0],  // 39
        [2, 3, 1, 1, 1, 3, 0, 0],  // 40
        [2, 3, 1, 3, 1, 1, 0, 0],  // 41
        [1, 1, 2, 1, 3, 3, 0, 0],  // 42
        [1, 1, 2, 3, 3, 1, 0, 0],  // 43
        [1, 3, 2, 1, 3, 1, 0, 0],  // 44
        [1, 1, 3, 1, 2, 3, 0, 0],  // 45
        [1, 1, 3, 3, 2, 1, 0, 0],  // 46
        [1, 3, 3, 1, 2, 1, 0, 0],  // 47
        [3, 1, 3, 1, 2, 1, 0, 0],  // 48
        [2, 1, 1, 3, 3, 1, 0, 0],  // 49
        [2, 3, 1, 1, 3, 1, 0, 0],  // 50
        [2, 1, 3, 1, 1, 3, 0, 0],  // 51
        [2, 1, 3, 3, 1, 1, 0, 0],  // 52
        [2, 1, 3, 1, 3, 1, 0, 0],  // 53
        [3, 1, 1, 1, 2, 3, 0, 0],  // 54
        [3, 1, 1, 3, 2, 1, 0, 0],  // 55
        [3, 3, 1, 1, 2, 1, 0, 0],  // 56
        [3, 1, 2, 1, 1, 3, 0, 0],  // 57
        [3, 1, 2, 3, 1, 1, 0, 0],  // 58
        [3, 3, 2, 1, 1, 1, 0, 0],  // 59
        [3, 1, 4, 1, 1, 1, 0, 0],  // 60
        [2, 2, 1, 4, 1, 1, 0, 0],  // 61
        [4, 3, 1, 1, 1, 1, 0, 0],  // 62
        [1, 1, 1, 2, 2, 4, 0, 0],  // 63
        [1, 1, 1, 4, 2, 2, 0, 0],  // 64
        [1, 2, 1, 1, 2, 4, 0, 0],  // 65
        [1, 2, 1, 4, 2, 1, 0, 0],  // 66
        [1, 4, 1, 1, 2, 2, 0, 0],  // 67
        [1, 4, 1, 2, 2, 1, 0, 0],  // 68
        [1, 1, 2, 2, 1, 4, 0, 0],  // 69
        [1, 1, 2, 4, 1, 2, 0, 0],  // 70
        [1, 2, 2, 1, 1, 4, 0, 0],  // 71
        [1, 2, 2, 4, 1, 1, 0, 0],  // 72
        [1, 4, 2, 1, 1, 2, 0, 0],  // 73
        [1, 4, 2, 2, 1, 1, 0, 0],  // 74
        [2, 4, 1, 2, 1, 1, 0, 0],  // 75
        [2, 2, 1, 1, 1, 4, 0, 0],  // 76
        [4, 1, 3, 1, 1, 1, 0, 0],  // 77
        [2, 4, 1, 1, 1, 2, 0, 0],  // 78
        [1, 3, 4, 1, 1, 1, 0, 0],  // 79
        [1, 1, 1, 2, 4, 2, 0, 0],  // 80
        [1, 2, 1, 1, 4, 2, 0, 0],  // 81
        [1, 2, 1, 2, 4, 1, 0, 0],  // 82
        [1, 1, 4, 2, 1, 2, 0, 0],  // 83
        [1, 2, 4, 1, 1, 2, 0, 0],  // 84
        [1, 2, 4, 2, 1, 1, 0, 0],  // 85
        [4, 1, 1, 2, 1, 2, 0, 0],  // 86
        [4, 2, 1, 1, 1, 2, 0, 0],  // 87
        [4, 2, 1, 2, 1, 1, 0, 0],  // 88
        [2, 1, 2, 1, 4, 1, 0, 0],  // 89
        [2, 1, 4, 1, 2, 1, 0, 0],  // 90
        [4, 1, 2, 1, 2, 1, 0, 0],  // 91
        [1, 1, 1, 1, 4, 3, 0, 0],  // 92
        [1, 1, 1, 3, 4, 1, 0, 0],  // 93
        [1, 3, 1, 1, 4, 1, 0, 0],  // 94
        [1, 1, 4, 1, 1, 3, 0, 0],  // 95
        [1, 1, 4, 3, 1, 1, 0, 0],  // 96
        [4, 1, 1, 1, 1, 3, 0, 0],  // 97
        [4, 1, 1, 3, 1, 1, 0, 0],  // 98
        [1, 1, 3, 1, 4, 1, 0, 0],  // 99
        [1, 1, 4, 1, 3, 1, 0, 0],  // 100
        [3, 1, 1, 1, 4, 1, 0, 0],  // 101
        [4, 1, 1, 1, 3, 1, 0, 0],  // 102
        [2, 1, 1, 4, 1, 2, 0, 0],  // 103
        [2, 1, 1, 2, 1, 4, 0, 0],  // 104
        [2, 1, 1, 2, 3, 2, 0, 0],  // 105
        [2, 3, 3, 1, 1, 1, 2, 0]   // 106
    ]
})()